/**
 * 
 */
package d.qapaper.tool;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * @author Kaven
 * 2011-5-24
 */
public class DateUtil {
	/**
	 * 日期格式(yyyy-MM-dd). 
	 * 参照({@link SimpleDateFormat}).
	 */
	public static final String DATE_PATTERN = "yyyy-MM-dd";

	/**
	 * 日期时间格式(yyyy-MM-dd HH:mm:ss). 
	 * 参照({@link SimpleDateFormat}).
	 */
	public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

	/**
	 * 时间格式(HH:mm:ss). 
	 * 参照({@link SimpleDateFormat}).
	 */
	public static final String TIME_PATTERN = "HH:mm:ss";

	/**
	 * 按指定的格式({@link SimpleDateFormat})格式化时间.
	 * 
	 * @param millis  时间毫秒数.
	 * @param pattern  格式
	 * @return 格式化后的时间
	 */
	public static String format(long millis, String pattern) {
		return format(new Date(millis), pattern);
	}

	/**
	 * 按指定的格式({@link SimpleDateFormat})格式化时间.
	 * 
	 * @param date  时间
	 * @param pattern  格式
	 * @return 格式化后的时间
	 */
	public static String format(Date date, String pattern) {
		DateFormat formatter = new SimpleDateFormat(pattern);
		return formatter.format(date);
	}

	/**
	 * 按默认的格式(yyyy-MM-dd)格式化日期.
	 * 
	 * @param date 时间
	 * @return 格式化后的日期
	 */
	public static String formartDate(Date date) {
		return format(date, DATE_PATTERN);
	}

	/**
	 * 按默认的格式(HH:mm:ss)格式化时间.
	 * 
	 * @param date 时间
	 * @return 格式化后的时间
	 */
	public static String formartTime(Date date) {
		return format(date, TIME_PATTERN);
	}

	/**
	 * 按默认的格式(yyyy-MM-dd HH:mm:ss)格式化日期时间.
	 * 
	 * @param date 时间
	 * @return 格式化后的日期时间.
	 */
	public static String formartDateTime(Date date) {
		return format(date, DATE_TIME_PATTERN);
	}

	/**
	 * 按指定的格式({@link SimpleDateFormat})格式化当前时间.
	 * @param pattern 格式
	 * @return 格式化后的当前时间
	 */
	public static String formatCurrent(String pattern) {
		return format(new Date(), pattern);
	}

	/**
	 * 按默认的格式(yyyy-MM-dd)格式化当前日期.
	 * 
	 * @return 格式化后的当前日期
	 */
	public static String formartCurrentDate() {
		return format(new Date(), DATE_PATTERN);
	}

	/**
	 * 按默认的格式(HH:mm:ss)格式化当前时间.
	 * 
	 * @return 格式化后的当前时间.
	 */
	public static String formartCurrentTime() {
		return format(new Date(), TIME_PATTERN);
	}

	/**
	 * 按默认的格式(yyyy-MM-dd HH:mm:ss)格式化当前日期时间.
	 * 
	 * @return 格式化后的当前日期时间.
	 */
	public static String formartCurrentDateTime() {
		return format(new Date(), DATE_TIME_PATTERN);
	}

	/**
	 * 获得今天凌晨0点0分对应的时间.
	 * 
	 * @return 今天凌晨0点0分对应的时间.
	 */
	public static Date getCurrentDate() {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * 获得指定时间当天凌晨0点0分对应的时间.
	 * 
	 * @param date 指定的时间.
	 * @return 指定时间当天凌晨0点0分对应的时间.
	 */
	public static Date getTheDate(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}

	/**
	 * 比较开始日期和结束日期.
	 * 
	 * @param start 开始日期
	 * @param end 结束日期
	 * @return 如果start和end均为<code>null</code>或他们代表的日期相同,返回0;
	 *         如果end为<code>null</code>,返回大于0的数字;
	 *         如果start为<code>null</code>,则start假设为当前日期和end比较,
	 *         start代表日期在end代表的日期前,则返回小于0的数字, 
	 *         start代表日期在end代表的日期后,则返回大于0的数字.
	 *         
	 */
	public static int compareDate(Date start, Date end) {
		if (start == null && end == null) {
			return 0;
		} else if (end == null) {
			return 1;
		} else if (start == null) {
			start = new Date();
		}
		start = getTheDate(start);
		end = getTheDate(end);
		return start.compareTo(end);
	}

	/**
	 * 从指定的日期字符串中解释出时间, 解释的规则({@link SimpleDateFormat})由pattern指定.
	 * 
	 * @param dateString 日期字符串
	 * @param pattern 解释规则
	 * @return 时间
	 */
	public static Date parse(String dateString, String pattern) {
		DateFormat formatter = new SimpleDateFormat(pattern);
		try {
			return formatter.parse(dateString);
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 返回指定时间点 <code>amount</code> 年后(前)的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param amount 年数,正数为加,负数为减.
	 * @return 增加(减少)指定年数后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	public static java.util.Date addYears(java.util.Date date, int amount) {
		return add(date, Calendar.YEAR, amount);
	}

	/**
	 * 返回指定时间点 <code>amount</code> 月后(前)的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param amount 月数,正数为加,负数为减.
	 * @return 增加(减少)指定月数后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	public static java.util.Date addMonths(java.util.Date date, int amount) {
		return add(date, Calendar.MONTH, amount);
	}

	/**
	 * 返回指定时间点 <code>amount</code> 星期后(前)的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param amount 星期数,正数为加,负数为减.
	 * @return 增加(减少)指定星期数后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	public static java.util.Date addWeeks(java.util.Date date, int amount) {
		return add(date, Calendar.WEEK_OF_YEAR, amount);
	}

	/**
	 * 返回指定时间点 <code>amount</code> 天后(前)的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param amount 天数,正数为加,负数为减.
	 * @return 增加(减少)指定天数后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	public static java.util.Date addDays(java.util.Date date, int amount) {
		return add(date, Calendar.DAY_OF_MONTH, amount);
	}

	/**
	 * 返回指定时间点 <code>amount</code> 小时后(前)的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param amount 小时数,正数为加,负数为减.
	 * @return 增加(减少)指定小时数后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	public static java.util.Date addHours(java.util.Date date, int amount) {
		return add(date, Calendar.HOUR_OF_DAY, amount);
	}

	/**
	 * 返回指定时间点 <code>amount</code> 分钟后(前)的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param amount 分钟数,正数为加,负数为减.
	 * @return 增加(减少)指定分钟数后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	public static java.util.Date addMinutes(java.util.Date date, int amount) {
		return add(date, Calendar.MINUTE, amount);
	}

	/**
	 * 返回指定时间点 <code>amount</code> 秒后(前)的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param amount 秒数,正数为加,负数为减.
	 * @return 增加(减少)指定秒数后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	public static java.util.Date addSeconds(java.util.Date date, int amount) {
		return add(date, Calendar.SECOND, amount);
	}

	/**
	 * 返回指定时间点 <code>amount</code> 豪秒后(前)的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param amount 豪秒数,正数为加,负数为减.
	 * @return 增加(减少)指定豪秒数后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	public static java.util.Date addMilliseconds(java.util.Date date, int amount) {
		return add(date, Calendar.MILLISECOND, amount);
	}

	/**
	 * 返回指定时间点增加(减少)一段时间后的时间. 返回新对象,源日期对象(<code>date</code>)不变.
	 * 
	 * @param date 源时间,不能为<code>null</code>.
	 * @param calendarField 增加(减少)的日历项.
	 * @param amount 数量,正数为加,负数为减.
	 * @return 日历项增加(减少)指定数目后的日期对象.
	 * 
	 * @throws IllegalArgumentException 如果源日期对象(<code>date</code>)为<code>null</code>.
	 */
	private static Date add(Date date, int calendarField, int amount) {
		if (date == null) {
			throw new IllegalArgumentException("日期对象不允许为null!");
		}
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(calendarField, amount);
		return c.getTime();
	}
}
